
package com.zz.framework.core.widget

import android.app.Activity
import android.content.Context
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.View.OnClickListener
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.annotation.LayoutRes
import androidx.fragment.app.Fragment
import com.zz.framework.R
import java.util.*

/**
 * Copyright © 2019 zanezhao All rights reserved.
 * Created by zanezhao on 2019-11-13 17:02.
 * @author: zanezhao 1820022519@qq.com
 * @version: V1.0
 */
class LoadingLayout @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = R.attr.styleLoadingLayout
) : FrameLayout(context, attrs, defStyleAttr) {

    internal var mEmptyImage: Int = 0
    internal var mEmptyText: CharSequence? = null

    internal var mErrorImage: Int = 0
    internal var mErrorText: CharSequence? = null
    internal var mRetryText: CharSequence? = null
    internal var mRetryButtonClickListener: View.OnClickListener = OnClickListener { v ->
        if (mRetryListener != null) {
            mRetryListener!!.onClick(v)
        }
    }
    internal var mRetryListener: View.OnClickListener? = null

    internal var mOnEmptyInflateListener: OnInflateListener? = null
    internal var mOnErrorInflateListener: OnInflateListener? = null

    internal var mTextColor: Int = 0
    internal var mTextSize: Int = 0
    internal var mButtonTextColor: Int = 0
    internal var mButtonTextSize: Int = 0
    internal var mButtonBackground: Drawable? = null
    internal var mEmptyResId = View.NO_ID
    internal var mLoadingResId = View.NO_ID
    internal var mErrorResId = View.NO_ID
    internal var mContentId = View.NO_ID

    internal var mLayouts: MutableMap<Int, View> = HashMap()


    internal var mInflater: LayoutInflater

    interface OnInflateListener {
        fun onInflate(inflated: View?)
    }

    init {
        mInflater = LayoutInflater.from(context)
        val a = context.obtainStyledAttributes(
            attrs,
            R.styleable.LoadingLayout,
            defStyleAttr,
            R.style.LoadingLayout_Style
        )
        mEmptyImage = a.getResourceId(R.styleable.LoadingLayout_llEmptyImage, View.NO_ID)
        mEmptyText = a.getString(R.styleable.LoadingLayout_llEmptyText)

        mErrorImage = a.getResourceId(R.styleable.LoadingLayout_llErrorImage, View.NO_ID)
        mErrorText = a.getString(R.styleable.LoadingLayout_llErrorText)
        mRetryText = a.getString(R.styleable.LoadingLayout_llRetryText)

        mTextColor = a.getColor(R.styleable.LoadingLayout_llTextColor, -0x666667)
        mTextSize = a.getDimensionPixelSize(R.styleable.LoadingLayout_llTextSize, dp2px(16f))

        mButtonTextColor = a.getColor(R.styleable.LoadingLayout_llButtonTextColor, -0x666667)
        mButtonTextSize =
            a.getDimensionPixelSize(R.styleable.LoadingLayout_llButtonTextSize, dp2px(16f))
        mButtonBackground = a.getDrawable(R.styleable.LoadingLayout_llButtonBackground)

        mEmptyResId = a.getResourceId(
            R.styleable.LoadingLayout_llEmptyResId,
            R.layout.view_loading_layout_empty
        )
        mLoadingResId = a.getResourceId(
            R.styleable.LoadingLayout_llLoadingResId,
            R.layout.view_loading_layout_loading
        )
        mErrorResId = a.getResourceId(
            R.styleable.LoadingLayout_llErrorResId,
            R.layout.view_loading_layout_error
        )
        a.recycle()
    }

    internal fun dp2px(dp: Float): Int {
        return (resources.displayMetrics.density * dp).toInt()
    }

    override fun onFinishInflate() {
        super.onFinishInflate()
        if (childCount == 0) {
            return
        }
        if (childCount > 1) {
            removeViews(1, childCount - 1)
        }
        val view = getChildAt(0)
        setContentView(view)
        showContent()
    }

    private fun setContentView(view: View) {
        mContentId = view.id
        mLayouts[mContentId] = view
    }

    fun setLoading(@LayoutRes id: Int): LoadingLayout {
        if (mLoadingResId != id) {
            remove(mLoadingResId)
            mLoadingResId = id
        }
        return this
    }

    fun setEmpty(@LayoutRes id: Int): LoadingLayout {
        if (mEmptyResId != id) {
            remove(mEmptyResId)
            mEmptyResId = id
        }
        return this
    }

    fun setOnEmptyInflateListener(listener: OnInflateListener): LoadingLayout {
        mOnEmptyInflateListener = listener
        if (mOnEmptyInflateListener != null && mLayouts.containsKey(mEmptyResId)) {
            listener.onInflate(mLayouts[mEmptyResId])
        }
        return this
    }

    fun setOnErrorInflateListener(listener: OnInflateListener): LoadingLayout {
        mOnErrorInflateListener = listener
        if (mOnErrorInflateListener != null && mLayouts.containsKey(mErrorResId)) {
            listener.onInflate(mLayouts[mErrorResId])
        }
        return this
    }

    fun setEmptyImage(@DrawableRes resId: Int): LoadingLayout {
        mEmptyImage = resId
        image(mEmptyResId, R.id.empty_image, mEmptyImage)
        return this
    }

    fun setEmptyText(value: String): LoadingLayout {
        mEmptyText = value
        text(mEmptyResId, R.id.empty_text, mEmptyText)
        return this
    }

    fun setErrorImage(@DrawableRes resId: Int): LoadingLayout {
        mErrorImage = resId
        image(mErrorResId, R.id.error_image, mErrorImage)
        return this
    }

    fun setErrorText(value: String): LoadingLayout {
        mErrorText = value
        text(mErrorResId, R.id.error_text, mErrorText)
        return this
    }

    fun setRetryText(text: String): LoadingLayout {
        mRetryText = text
        text(mErrorResId, R.id.retry_button, mRetryText)
        return this
    }

    fun setRetryListener(listener: View.OnClickListener): LoadingLayout {
        mRetryListener = listener
        return this
    }


    //    public LoadingLayout setTextColor(@ColorInt int color) {
    //        mTextColor = color;
    //        return this;
    //    }
    //    public LoadingLayout setTextSize(@ColorInt int dp) {
    //        mTextColor = dp2px(dp);
    //        return this;
    //    }
    //    public LoadingLayout setButtonTextColor(@ColorInt int color) {
    //        mButtonTextColor = color;
    //        return this;
    //    }
    //    public LoadingLayout setButtonTextSize(@ColorInt int dp) {
    //        mButtonTextColor = dp2px(dp);
    //        return this;
    //    }
    //    public LoadingLayout setButtonBackground(Drawable drawable) {
    //        mButtonBackground = drawable;
    //        return this;
    //    }

    fun showLoading() {
        show(mLoadingResId)
    }

    fun showEmpty() {
        show(mEmptyResId)
    }

    fun showError() {
        show(mErrorResId)
    }

    fun showContent() {
        show(mContentId)
    }

    private fun show(layoutId: Int) {
        for (view in mLayouts.values) {
            view.visibility = View.GONE
        }
        layout(layoutId)!!.visibility = View.VISIBLE
    }

    private fun remove(layoutId: Int) {
        if (mLayouts.containsKey(layoutId)) {
            val vg = mLayouts.remove(layoutId)
            removeView(vg)
        }
    }

    private fun layout(layoutId: Int): View? {
        if (mLayouts.containsKey(layoutId)) {
            return mLayouts[layoutId]
        }
        val layout = mInflater.inflate(layoutId, this, false)
        layout.visibility = View.GONE
        addView(layout)
        mLayouts[layoutId] = layout

        if (layoutId == mEmptyResId) {
            val img = layout.findViewById<ImageView>(R.id.empty_image)
            img?.setImageResource(mEmptyImage)
            val view = layout.findViewById<TextView>(R.id.empty_text)
            if (view != null) {
                view.text = mEmptyText
                view.setTextColor(mTextColor)
                view.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize.toFloat())
            }
            if (mOnEmptyInflateListener != null) {
                mOnEmptyInflateListener!!.onInflate(layout)
            }
        } else if (layoutId == mErrorResId) {
            val img = layout.findViewById<View>(R.id.error_image) as ImageView
            if (img != null && mErrorImage > 0) {
                img.setImageResource(mErrorImage)
            }
            val txt = layout.findViewById<View>(R.id.error_text) as TextView
            if (txt != null) {
                txt.text = mErrorText
                txt.setTextColor(mTextColor)
                txt.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize.toFloat())
            }
            val btn = layout.findViewById<View>(R.id.retry_button) as TextView
            if (btn != null) {
                btn.text = mRetryText
                btn.setTextColor(mButtonTextColor)
                btn.setTextSize(TypedValue.COMPLEX_UNIT_PX, mButtonTextSize.toFloat())
                btn.background = mButtonBackground
                btn.setOnClickListener(mRetryButtonClickListener)
            }
            if (mOnErrorInflateListener != null) {
                mOnErrorInflateListener!!.onInflate(layout)
            }
        }
        return layout
    }

    private fun text(layoutId: Int, ctrlId: Int, value: CharSequence?) {
        if (mLayouts.containsKey(layoutId)) {
            val view = mLayouts[layoutId]!!.findViewById<View>(ctrlId) as TextView
            if (view != null) {
                view.text = value
            }
        }
    }

    private fun image(layoutId: Int, ctrlId: Int, resId: Int) {
        if (mLayouts.containsKey(layoutId)) {
            val view = mLayouts[layoutId]!!.findViewById<View>(ctrlId) as ImageView
            view?.setImageResource(resId)
        }
    }

    companion object {
        fun wrap(activity: Activity): LoadingLayout {
            return wrap(
                (activity.findViewById<View>(android.R.id.content) as ViewGroup).getChildAt(
                    0
                )
            )
        }

        fun wrap(fragment: Fragment): LoadingLayout {
            return wrap(fragment.view)
        }

        fun wrap(view: View?): LoadingLayout {
            if (view == null) {
                throw RuntimeException("content view can not be null")
            }
            val parent = view.parent as ViewGroup
            if (view == null) {
                throw RuntimeException("parent view can not be null")
            }
            val lp = view.layoutParams
            val index = parent.indexOfChild(view)
            parent.removeView(view)

            val layout = LoadingLayout(view.context)
            parent.addView(layout, index, lp)
            layout.addView(view)
            layout.setContentView(view)
            return layout
        }
    }
}
